package com.ideaaedi.log4j2.defender.defender;

import com.ideaaedi.log4j2.defender.strategy.DefenderStrategy;
import com.ideaaedi.log4j2.defender.util.DefenderUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.message.Message;

import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 针对正则表达式的脱敏
 *
 * @author JustryDeng
 * @since 2021/7/21 1:15:15
 */
public class DefaultRegexMessageDefender extends AbstractLog4j2MessageDefender<Pattern> {
    
    public DefaultRegexMessageDefender(Map<Pattern, DefenderStrategy> patternDesensitizationStrategyMap,
                                       List<Log4j2MessageDefender> plugins) {
        super(patternDesensitizationStrategyMap, plugins);
    }
    
    @Override
    public void doDesensitize(Message message, StringBuilder buffer,
                              Map<Pattern, DefenderStrategy> strategyMap) {
        String strData = message.getFormattedMessage();
        if (StringUtils.isBlank(strData)) {
            return;
        }
        StringBuilder sb = new StringBuilder(strData);

        Pattern pattern;
        Matcher matcher;
        String tmpMsg;
        String valueAfterDesensitization;

        /*
         * 循环匹配正则
         *
         * 注意:后一个正则脱敏，依赖于前一个正则脱敏后的结果。
         *      也就是说:如果同一个位置，可能被多个正则匹配到，
         *              进行处理；这里之所以不处理这个小问题，是因为
         *              在实际情况下，按正常业务需求写的正则，是不会
         *              发生“匹配重叠”这样的情况的，按正常业务需求写
         *              的正则，下一个正则几乎不可能匹配到之前正则匹
         *              配到的内容。
         */
        for (Map.Entry<Pattern, DefenderStrategy> entry : strategyMap.entrySet()) {
            pattern = entry.getKey();
            matcher = pattern.matcher(strData);
            while (matcher.find()) {
                tmpMsg = matcher.group();
                valueAfterDesensitization = DefenderUtil.doReplace(tmpMsg, entry.getValue());
                sb.replace(matcher.start(), matcher.end(), valueAfterDesensitization);
                strData = sb.toString();
            }
        }
        buffer.append(strData);
    }
    
    @Override
    public boolean support(LogEvent event) {
        return true;
    }
}
